(() ->
	root = this
	root = exports if exports?

	class Surface 
		constructor: (owner, target) ->
			@info =
				owner: owner
				io: Surface.type.UNDEFINED
				editable: true
				linkTo: null
			@target = target

			return this

		setType : (io) ->
			@info.io = io
		link : (s) ->
			@info.linkTo = s

		@type =
			UNDEFINED: 0
			IN: 1
			OUT: -1

	###
	对于Cube中的一段代码来说，运行环境的this包含以下信息：
	this.port: an array[0-5] for each port data, direct assign value to a port whose type is output, assign to other port will take no effect. see runtime.test.coffee for more usage info. 
	dataType: int number, with only 0-2147483647 avaliable
	###
	class Cube
		constructor: (target) ->
			@id = Math.random().toString()
			@target = target
			@code = ''
			@editable = true
			@surfaces = []
			@type = Cube.type.CODE
			@_genSurfaces()

		setTarget : (target) ->
			@target = target

		_genSurfaces : () ->
			for i in [0..5]
				this.surfaces.push (new Surface this, null)

		@type =
			CODE : 1
			LIGHT : 2
			ENGINE : 3

	###
	lighting if any port is not 0
	###
	class CubeLight extends Cube
		constructor: (target) ->
			super(target)
			for i in [0..5]
				this.surfaces[i].info.editable = false
				this.surfaces[i].info.io = Surface.type.IN
			@lighting = false
			@editable = false
			@type = Cube.type.LIGHT

		perform : (port) ->
			@lighting = false
			for i in [0..5]
				@lighting = true if port[i]? and port[i] isnt 0

	###
	speed is controled by all port(connected with INPUT type) average value. data should be 0 - 255.
	###
	class CubeEngine extends Cube
		constructor: (target) ->
			super(target)
			for i in [0..5]
				this.surfaces[i].info.editable = false
			@direction = 0
			@speed = 0
			@movement = 
				x : 0
				y: 0
				z : 0
			@editable = false
			@type = Cube.type.ENGINE

		perform : (port) ->
			total = 0
			count = 0
			for i in [0..5]
				if port[i]?
					count++
					total += Math.abs port[i], 255
			total /= count
			@speed = total / 10
			@movement = 
				x : 0
				y : 0
				z : 0
			switch @direction
				when SURF_NUM.X_POS then @movement.x = 1
				when SURF_NUM.X_NEG then @movement.x = -1
				when SURF_NUM.Y_POS then @movement.y = 1
				when SURF_NUM.Y_NEG then @movement.y = -1
				when SURF_NUM.Z_POS then @movement.z = 1
				when SURF_NUM.Z_NEG then @movement.z = -1

			@movement =
				x : @movement.x * @speed
				y : @movement.y * @speed
				z : @movement.z * @speed

	root.Surface = Surface
	root.Cube = Cube
	root.CubeLight = CubeLight
	root.CubeEngine = CubeEngine
)()